package com.faner.fast.excel.aop;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ArrayUtil;
import com.faner.fast.excel.annotation.ResponseExcel;
import com.faner.fast.excel.kit.ExcelConstants;
import com.faner.fast.excel.processor.NameProcessor;
import com.faner.fast.util.ThreadLocalUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * @date 2020/3/29
 */
@Slf4j
@Aspect
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
public class DynamicNameAspect {
    public static final String EXCEL_NAME_KEY = "__EXCEL_NAME_KEY__";
    private final NameProcessor processor;

    @SneakyThrows
    @Before("@annotation(excel)")
    public void around(JoinPoint point, ResponseExcel excel) {
        MethodSignature ms = (MethodSignature) point.getSignature();
        String name = processor.doDetermineName(point.getArgs(), ms.getMethod(), excel.name());
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        Objects.requireNonNull(requestAttributes).setAttribute(EXCEL_NAME_KEY, name, RequestAttributes.SCOPE_REQUEST);
    }

    @After("@annotation(excel)")
    public void after(JoinPoint point, ResponseExcel excel) {
        log.info("DynamicNameAspect aop @after 执行");
    }

    @AfterReturning("@annotation(excel)")
    public void AfterReturning(JoinPoint point, ResponseExcel excel) {
        Object threadLocalInclude = ThreadLocalUtil.get(ExcelConstants.EXCEL_INCLUDE);
        if (threadLocalInclude != null && threadLocalInclude.getClass().isArray()) {
            String[] include = excel.include();
            String[] strings = ArrayUtil.addAll(include, (String[]) threadLocalInclude);
            AnnotationUtil.setValue(excel, ExcelConstants.EXCEL_INCLUDE, strings);
        }
        Object threadLocalexclude = ThreadLocalUtil.get(ExcelConstants.EXCEL_EXCLUDE);
        if (threadLocalexclude != null && threadLocalexclude.getClass().isArray()) {
            String[] exclude = excel.exclude();
            String[] strings = ArrayUtil.addAll(exclude, (String[]) threadLocalexclude);
            AnnotationUtil.setValue(excel, ExcelConstants.EXCEL_EXCLUDE, strings);
        }
    }


    @AfterThrowing("@annotation(excel)")
    public void AfterThrowing(ResponseExcel excel) {
        log.info("DynamicNameAspect aop @AfterThrowing 执行");
        ThreadLocalUtil.clear();
    }
}